home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume13 / rpc3.9 / part11 < prev    next >
Encoding:
Internet Message Format  |  1988-02-27  |  62.8 KB

  1. Subject:  v13i088:  Sun RPC, release 3.9, Part11/15
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Stephen X. Nahm <sxn@Sun.COM>
  7. Posting-number: Volume 13, Issue 88
  8. Archive-name: rpc3.9/part11
  9.  
  10. #! /bin/sh
  11. # This is a shell archive. To extract, remove the header and type "sh filename"
  12. #
  13. echo x - doc
  14. echo creating directory doc
  15. mkdir doc
  16. cd doc
  17. echo x - rpc.prog.ms
  18. sed -e 's/^X//' > rpc.prog.ms <<'Funky_Stuff'
  19. X.\" @(#)rpc.prog.ms    1.2 87/11/09 3.9 RPCSRC
  20. X.de BT
  21. X.if \\n%=1 .tl ''- % -''
  22. X..
  23. X.IX "Network Programming" "" "" "" PAGE MAJOR
  24. X.nr OF 0
  25. X.ND
  26. X.\" prevent excess underlining in nroff
  27. X.if n .fp 2 R
  28. X.OH 'Remote Procedure Call Programming Guide''Page %'
  29. X.EH 'Page %''Remote Procedure Call Programming Guide'
  30. X.SH
  31. \&Remote Procedure Call Programming Guide
  32. X.nr OF 1
  33. X.IX "RPC Programming Guide"
  34. X.LP
  35. This document is intended for programmers who wish to write network 
  36. applications using remote procedure calls (explained below), thus
  37. avoiding low-level system primitives based on sockets.  The reader
  38. must be familiar with the C programming language, and should have a 
  39. working knowledge of network theory.
  40. X.SH
  41. X.IX rpcgen "" \fIrpcgen\fP
  42. X.I
  43. NOTE: Before attempting to write a network application, or to convert an
  44. existing non-network application to run over the network, you should
  45. be familiar with the material in this chapter.  However, for most
  46. applications, you can circumvent the need to cope with the kinds of
  47. details presented here by using the
  48. X.I rpcgen
  49. protocol compiler, which is described in detail in the next chapter,
  50. the
  51. \fI\f(LBrpcgen\fR Programming Guide\fI\.
  52. The
  53. \fRGenerating XDR Routines\fI
  54. section of that chapter contains the complete source for a working RPC
  55. service\(ema remote directory listing service which uses
  56. X.B rpcgen 
  57. to generate XDR routines as well as client and server stubs.
  58. X.LP
  59. X.LP
  60. What are remote procedure calls?  Simply put, they are the high-level
  61. communications paradigm used in the operating system.
  62. RPC presumes the existence of
  63. low-level networking mechanisms (such as TCP/IP and UDP/IP), and upon them
  64. it implements a logical client to server communications system designed
  65. specifically for the support of network applications.  With RPC, the client
  66. makes a procedure call to send a data packet to the server.  When the
  67. packet arrives, the server calls a dispatch routine, performs whatever
  68. service is requested, sends back the reply, and the procedure call returns
  69. to the client.
  70. X.NH 0
  71. \&Layers of RPC
  72. X.IX "layers of RPC"
  73. X.IX "RPC" "layers"
  74. X.LP
  75. The RPC interface can be seen as being divided into three layers.\**
  76. X.FS
  77. For a complete specification of the routines in the remote procedure
  78. call Library, see the
  79. X.I rpc (3N)
  80. manual page.
  81. X.FE
  82. X.LP
  83. X.I "The Highest Layer:"
  84. X.IX RPC "The Highest Layer"
  85. The highest layer is totally transparent to the operating system, 
  86. machine and network upon which is is run.  It's probably best to 
  87. think of this level as a way of \fIusing\fP RPC, rather than as 
  88. a \fIpart of\fP RPC proper.  Programmers who write RPC routines 
  89. should (almost) always make this layer available to others by way 
  90. of a simple C front end to that entirely hides the networking.   
  91. X.LP 
  92. To illustrate, at this level a program can simply make a call to
  93. X.I rnusers ,
  94. a C routine which returns the number of users on a remote machine.
  95. The user is not explicitly aware of using RPC \(em they simply 
  96. call a procedure, just as they would call
  97. X.I malloc
  98. X.LP
  99. X.I "The Middle Layer:"
  100. X.IX RPC "The Middle Layer"
  101. The middle layer is really "RPC proper."  Here, the user doesn't 
  102. need to consider details about sockets, the UNIX system, or other low-level 
  103. implementation mechanisms.  They simple make remote procedure calls 
  104. to routines on other machines.  The selling point here is simplicity.  
  105. It's this layer that allows RPC to pass the "hello world" test \(em 
  106. simple things should be simple.  The middle-layer routines are used 
  107. for most applications.
  108. X.LP
  109. RPC calls are made with the system routines
  110. X.I registerrpc
  111. X.I callrpc
  112. and
  113. X.I svc_run .
  114. The first two of these are the most fundamental:
  115. X.I registerrpc 
  116. obtains a unique system-wide procedure-identification number, and
  117. X.I callrpc 
  118. actually executes a remote procedure call.  At the middle level, a 
  119. call to 
  120. X.I rnusers
  121. is implemented by way of these two routines.
  122. X.LP
  123. The middle layer is unfortunately rarely used in serious programming 
  124. due to its inflexibility (simplicity).  It does not allow timeout 
  125. specifications or the choice of transport.  It allows no UNIX
  126. process control or flexibility in case of errors.  It doesn't support
  127. multiple kinds of call authentication.  The programmer rarely needs 
  128. all these kinds of control, but one or two of them is often necessary.
  129. X.LP
  130. X.I "The Lowest Layer:"
  131. X.IX RPC "The Lowest Layer"
  132. The lowest layer does allow these details to be controlled by the 
  133. programmer, and for that reason it is often necessary.  Programs 
  134. written at this level are also most efficient, but this is rarely a
  135. real issue \(em since RPC clients and servers rarely generate 
  136. heavy network loads.
  137. X.LP
  138. Although this document only discusses the interface to C,
  139. remote procedure calls can be made from any language.
  140. Even though this document discusses RPC
  141. when it is used to communicate
  142. between processes on different machines,
  143. it works just as well for communication
  144. between different processes on the same machine.
  145. X.
  146. X.NH 2
  147. \&The RPC Paradigm
  148. X.IX "paradigm of RPC"
  149. X.IX "RPC" "paradigm"
  150. X.LP
  151. Here is a diagram of the RPC paradigm:
  152. X.LP
  153. X.\" This is a PIC diagram
  154. X.PS
  155. L1: arrow down 1i "client " rjust "program " rjust
  156. L2: line right 1i "\fIcallrpc()\fP" "function"
  157. move up 1.5i; line dotted down 6i; move up 4.5i
  158. arrow right 1i
  159. L3: arrow down 1i "execute " rjust "request " rjust
  160. L4: arrow right 1.5i "call" "service"
  161. L5: arrow down 1i " service" ljust " executes" ljust
  162. L6: arrow left 1.5i "\fIreturn\fP" "answer"
  163. L7: arrow down 1i "request " rjust "completed " rjust
  164. L8: line left 1i
  165. arrow left 1i "\fIreturn\fP" "reply"
  166. L9: arrow down 1i "program " rjust "continues " rjust
  167. line dashed down from L2 to L9
  168. line dashed down from L4 to L7
  169. line dashed up 1i from L3 "service " rjust "daemon " rjust
  170. arrow dashed down 1i from L8
  171. move right 1i from L3
  172. box invis "Machine B"
  173. move left 0.7i from L2; move down
  174. box invis "Machine A"
  175. X.PE
  176. X.
  177. X.KS
  178. X.NH 1
  179. \&Higher Layers of RPC
  180. X.NH 2
  181. \&Highest Layer
  182. X.IX "highest layer of RPC"
  183. X.IX RPC "highest layer"
  184. X.LP
  185. Imagine you're writing a program that needs to know
  186. how many users are logged into a remote machine.
  187. You can do this by calling the RPC library routine
  188. X.IX rusers "" "" "\fIrusers\fP" PAGE MAJOR
  189. X.I rnusers ,
  190. as illustrated below:
  191. X.ie t .DS
  192. X.el .DS L
  193. X.ft CW
  194. #include <stdio.h>
  195.  
  196. main(argc, argv)
  197.     int argc;
  198.     char **argv;
  199. {
  200.     int num;
  201.  
  202.     if (argc < 2) {
  203.         fprintf(stderr, "usage: rnusers hostname\en");
  204.         exit(1);
  205.     }
  206.     if ((num = rnusers(argv[1])) < 0) {
  207.         fprintf(stderr, "error: rnusers\en");
  208.         exit(-1);
  209.     }
  210.     printf("%d users on %s\en", num, argv[1]);
  211.     exit(0);
  212. }
  213. X.DE
  214. X.KE
  215. RPC library routines such as
  216. X.I rnusers
  217. are in the RPC services library
  218. X.I librpcsvc.a
  219. Thus, the program above should be compiled with
  220. X.DS
  221. X.ft CW
  222. % cc \fIprogram\fP.c -lrpcsvc
  223. X.DE
  224. X.I rnusers ,
  225. like the other RPC library routines, is documented in section 3R 
  226. of the
  227. X.I "System Interface Manual for the Sun Workstation" ,
  228. the same section which documents the standard Sun RPC services.  
  229. X.IX "RPC Services"
  230. See the 
  231. X.I intro (3R)
  232. manual page for an explanation of the documentation strategy 
  233. for these services and their RPC protocols.
  234. X.LP
  235. Here are some of the RPC service library routines available to the 
  236. C programmer:
  237. X.TS
  238. box tab (&) ;
  239. cfI cfI
  240. lfL l .
  241. Routine&Description
  242. _
  243. X.sp.5
  244. rnusers&Return number of users on remote machine
  245. rusers&Return information about users on remote machine
  246. havedisk&Determine if remote machine has disk
  247. rstats&Get performance data from remote kernel
  248. rwall&Write to specified remote machines
  249. yppasswd&Update user password in Yellow Pages
  250. X.TE
  251. X.LP
  252. Other RPC services \(em for example
  253. X.I ether
  254. X.I mount
  255. X.I rquota
  256. and
  257. X.I spray
  258. \(em are not available to the C programmer as library routines.
  259. They do, however,
  260. have RPC program numbers so they can be invoked with
  261. X.I callrpc
  262. which will be discussed in the next section.  Most of them also 
  263. have compilable 
  264. X.I rpcgen (1)
  265. protocol description files.  (The
  266. X.I rpcgen
  267. protocol compiler radically simplifies the process of developing
  268. network applications.  See the
  269. \fI\f(LBrpcgen\fP Programming Guide\fR
  270. chapter for detailed information about 
  271. X.I rpcgen 
  272. and 
  273. X.I rpcgen 
  274. protocol description files).
  275. X.
  276. X.KS
  277. X.NH 2
  278. \&Intermediate Layer
  279. X.IX "intermediate layer of RPC"
  280. X.IX "RPC" "intermediate layer"
  281. X.LP
  282. The simplest interface, which explicitly makes RPC calls, uses the 
  283. functions
  284. X.I callrpc
  285. and
  286. X.I registerrpc
  287. Using this method, the number of remote users can be gotten as follows:
  288. X.ie t .DS
  289. X.el .DS L
  290. #include <stdio.h>
  291. #include <rpc/rpc.h>
  292. #include <utmp.h>
  293. #include <rpcsvc/rusers.h>
  294.  
  295. main(argc, argv)
  296.     int argc;
  297.     char **argv;
  298. {
  299.     unsigned long nusers;
  300.     int stat;
  301.  
  302.     if (argc < 2) {
  303.         fprintf(stderr, "usage: nusers hostname\en");
  304.         exit(-1);
  305.     }
  306.     if (stat = callrpc(argv[1],
  307.       RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM,
  308.       xdr_void, 0, xdr_u_long, &nusers) != 0) {
  309.         clnt_perrno(stat);
  310.         exit(1);
  311.     }
  312.     printf("%d users on %s\en", nusers, argv[1]);
  313.     exit(0);
  314. }
  315. X.DE
  316. X.KE
  317. Each RPC procedure is uniquely defined by a program number, 
  318. version number, and procedure number.  The program number 
  319. specifies a group of related remote procedures, each of 
  320. which has a different procedure number.  Each program also 
  321. has a version number, so when a minor change is made to a 
  322. remote service (adding a new procedure, for example), a new 
  323. program number doesn't have to be assigned.  When you want 
  324. to call a procedure to find the number of remote users, you 
  325. look up the appropriate program, version and procedure numbers
  326. in a manual, just as you look up the name of a memory allocator 
  327. when you want to allocate memory.
  328. X.LP
  329. The simplest way of making remote procedure calls is with the the RPC 
  330. library routine
  331. X.I callrpc
  332. It has eight parameters.  The first is the name of the remote server 
  333. machine.  The next three parameters are the program, version, and procedure 
  334. numbers\(emtogether they identify the procedure to be called.
  335. The fifth and sixth parameters are an XDR filter and an argument to
  336. be encoded and passed to the remote procedure.  
  337. The final two parameters are a filter for decoding the results 
  338. returned by the remote procedure and a pointer to the place where 
  339. the procedure's results are to be stored.  Multiple arguments and
  340. results are handled by embedding them in structures.  If 
  341. X.I callrpc 
  342. completes successfully, it returns zero; else it returns a nonzero 
  343. value.  The return codes (of type
  344. X.I "enum
  345. cast into an integer) are found in 
  346. X.I <rpc/clnt.h> .
  347. X.LP
  348. Since data types may be represented differently on different machines,
  349. X.I callrpc 
  350. needs both the type of the RPC argument, as well as
  351. a pointer to the argument itself (and similarly for the result).  For
  352. X.I RUSERSPROC_NUM ,
  353. the return value is an
  354. X.I "unsigned long"
  355. so
  356. X.I callrpc 
  357. has
  358. X.I xdr_u_long 
  359. as its first return parameter, which says
  360. that the result is of type
  361. X.I "unsigned long"
  362. and
  363. X.I &nusers 
  364. X.IX "nusers&" "" \fI&nusers\fP
  365. as its second return parameter,
  366. which is a pointer to where the long result will be placed.  Since
  367. X.I RUSERSPROC_NUM 
  368. takes no argument, the argument parameter of
  369. X.I callrpc 
  370. is
  371. X.I xdr_void .
  372. X.LP
  373. After trying several times to deliver a message, if
  374. X.I callrpc 
  375. gets no answer, it returns with an error code.
  376. The delivery mechanism is UDP,
  377. which stands for User Datagram Protocol.
  378. Methods for adjusting the number of retries
  379. or for using a different protocol require you to use the lower
  380. layer of the RPC library, discussed later in this document.
  381. The remote server procedure
  382. corresponding to the above might look like this:
  383. X.ie t .DS
  384. X.el .DS L
  385. X.ft CW
  386. X.ft CW
  387. char *
  388. nuser(indata)
  389.     char *indata;
  390. {
  391.     static int nusers;
  392.  
  393. X.ft I
  394.     /*
  395.      * Code here to compute the number of users
  396.      * and place result in variable \fInusers\fP.
  397.      */
  398. X.ft CW
  399.     return((char *)&nusers);
  400. }
  401. X.DE
  402. X.LP
  403. It takes one argument, which is a pointer to the input
  404. of the remote procedure call (ignored in our example),
  405. and it returns a pointer to the result.
  406. In the current version of C,
  407. character pointers are the generic pointers,
  408. so both the input argument and the return value are cast to
  409. X.I "char *"
  410. X.LP
  411. Normally, a server registers all of the RPC calls it plans
  412. to handle, and then goes into an infinite loop waiting to service requests.
  413. In this example, there is only a single procedure
  414. to register, so the main body of the server would look like this:
  415. X.ie t .DS
  416. X.el .DS L
  417. X.ft CW
  418. #include <stdio.h>
  419. #include <rpc/rpc.h>
  420. #include <utmp.h>
  421. #include <rpcsvc/rusers.h>
  422.  
  423. char *nuser();
  424.  
  425. main()
  426. {
  427.     registerrpc(RUSERSPROG, RUSERSVERS, RUSERSPROC_NUM,
  428.         nuser, xdr_void, xdr_u_long);
  429.     svc_run();        /* \fINever returns\fP */
  430.     fprintf(stderr, "Error: svc_run returned!\en");
  431.     exit(1);
  432. }
  433. X.DE
  434. X.LP
  435. The
  436. X.I registerrpc
  437. routine registers a C procedure as corresponding to a
  438. given RPC procedure number.  The first three parameters,
  439. X.I RUSERPROG ,
  440. X.I RUSERSVERS ,
  441. and
  442. X.I RUSERSPROC_NUM 
  443. are the program, version, and procedure numbers
  444. of the remote procedure to be registered;
  445. X.I nuser 
  446. is the name of the local procedure that implements the remote
  447. procedure; and
  448. X.I xdr_void 
  449. and
  450. X.I xdr_u_long 
  451. are the XDR filters for the remote procedure's arguments and
  452. results, respectively.  (Multiple arguments or multiple results
  453. are passed as structures).
  454. X.LP
  455. Only the UDP transport mechanism can use
  456. X.I registerrpc
  457. thus, it is always safe in conjunction with calls generated by
  458. X.I callrpc .
  459. X.SH
  460. \&WARNING:
  461. X.IX "UDP 8K warning"
  462. The UDP transport mechanism can only deal with
  463. arguments and results less than 8K bytes in length.
  464. X.LP
  465. X.LP
  466. After registering the local procedure, the server program's
  467. main procedure calls
  468. X.I svc_run ,
  469. the RPC library's remote procedure dispatcher.  It is this 
  470. function that calls the remote procedures in response to RPC
  471. call messages.  Note that the dispatcher takes care of decoding
  472. remote procedure arguments and encoding results, using the XDR
  473. filters specified when the remote procedure was registered.
  474. X.
  475. X.NH 2
  476. \&Assigning Program Numbers
  477. X.IX "program number assignment"
  478. X.IX "assigning program numbers"
  479. X.LP
  480. Program numbers are assigned in groups of 
  481. X.I 0x20000000 
  482. according to the following chart:
  483. X.DS
  484. X.ft CW
  485.        0x0 - 0x1fffffff    \fRDefined by Sun\fP
  486. 0x20000000 - 0x3fffffff    \fRDefined by user\fP
  487. 0x40000000 - 0x5fffffff    \fRTransient\fP
  488. 0x60000000 - 0x7fffffff    \fRReserved\fP
  489. 0x80000000 - 0x9fffffff    \fRReserved\fP
  490. 0xa0000000 - 0xbfffffff    \fRReserved\fP
  491. 0xc0000000 - 0xdfffffff    \fRReserved\fP
  492. 0xe0000000 - 0xffffffff    \fRReserved\fP
  493. X.ft R
  494. X.DE
  495. Sun Microsystems administers the first group of numbers, which
  496. should be identical for all Sun customers.  If a customer
  497. develops an application that might be of general interest, that
  498. application should be given an assigned number in the first
  499. range.  The second group of numbers is reserved for specific
  500. customer applications.  This range is intended primarily for
  501. debugging new programs.  The third group is reserved for
  502. applications that generate program numbers dynamically.  The
  503. final groups are reserved for future use, and should not be
  504. used.
  505. X.LP
  506. To register a protocol specification, send a request by network 
  507. mail to
  508. X.I rpc@sun
  509. or write to:
  510. X.DS
  511. RPC Administrator
  512. Sun Microsystems
  513. 2550 Garcia Ave.
  514. Mountain View, CA 94043
  515. X.DE
  516. Please include a compilable 
  517. X.I rpcgen 
  518. ``.x'' file describing your protocol.
  519. You will be given a unique program number in return.
  520. X.IX "RPC" "administration"
  521. X.IX "administration of RPC"
  522. X.LP
  523. The RPC program numbers and protocol specifications 
  524. of standard Sun RPC services can be
  525. found in the include files in 
  526. X.I "/usr/include/rpcsvc" .
  527. These services, however, constitute only a small subset 
  528. of those which have been registered.  The complete list of 
  529. registered programs, as of the time when this manual was 
  530. printed, is:
  531. X.TS H
  532. box tab (&) ;
  533. lfBI lfBI lfBI
  534. lfL lfL lfI .
  535. RPC Number&Program&Description
  536. _
  537. X.TH
  538. X.sp.5
  539. 100000&PMAPPROG&portmapper
  540. 100001&RSTATPROG&remote stats            
  541. 100002&RUSERSPROG&remote users            
  542. 100003&NFSPROG&nfs                     
  543. 100004&YPPROG&Yellow Pages            
  544. 100005&MOUNTPROG&mount demon             
  545. 100006&DBXPROG&remote dbx              
  546. 100007&YPBINDPROG&yp binder               
  547. 100008&WALLPROG&shutdown msg            
  548. 100009&YPPASSWDPROG&yppasswd server         
  549. 100010ÐERSTATPROGðer stats             
  550. 100011&RQUOTAPROG&disk quotas             
  551. 100012&SPRAYPROG&spray packets           
  552. 100013&IBM3270PROG&3270 mapper             
  553. 100014&IBMRJEPROG&RJE mapper              
  554. 100015&SELNSVCPROG&selection service       
  555. 100016&RDATABASEPROG&remote database access  
  556. 100017&REXECPROG&remote execution        
  557. 100018&ALICEPROG&Alice Office Automation 
  558. 100019&SCHEDPROG&scheduling service      
  559. 100020&LOCKPROG&local lock manager      
  560. 100021&NETLOCKPROG&network lock manager    
  561. 100022&X25PROG&x.25 inr protocol       
  562. 100023&STATMON1PROG&status monitor 1        
  563. 100024&STATMON2PROG&status monitor 2        
  564. 100025&SELNLIBPROG&selection library       
  565. 100026&BOOTPARAMPROG&boot parameters service 
  566. 100027&MAZEPROG&mazewars game           
  567. 100028&YPUPDATEPROG&yp update               
  568. 100029&KEYSERVEPROG&key server              
  569. 100030&SECURECMDPROG&secure login            
  570. 100031&NETFWDIPROG&nfs net forwarder init    
  571. 100032&NETFWDTPROG&nfs net forwarder trans    
  572. 100033&SUNLINKMAP_PROG&sunlink MAP        
  573. 100034&NETMONPROG&network monitor        
  574. 100035&DBASEPROG&lightweight database    
  575. 100036&PWDAUTHPROG&password authorization    
  576. 100037&TFSPROG&translucent file svc    
  577. 100038&NSEPROG&nse server        
  578. 100039&NSE_ACTIVATE_PROG&nse activate daemon    
  579. X.sp .2i
  580. 150001&PCNFSDPROG&pc passwd authorization 
  581. X.sp .2i
  582. 200000&PYRAMIDLOCKINGPROG&Pyramid-locking         
  583. 200001&PYRAMIDSYS5&Pyramid-sys5            
  584. 200002&CADDS_IMAGE&CV cadds_image        
  585. X.sp .2i
  586. 300001&ADT_RFLOCKPROG&ADT file locking    
  587. X.TE
  588. X.
  589. X.NH 2
  590. \&Passing Arbitrary Data Types
  591. X.IX "passing arbitrary data types"
  592. X.IX "arbitrary data types"
  593. X.LP
  594. In the previous example, the RPC call passes a single
  595. X.I "unsigned long"
  596. RPC can handle arbitrary data structures, regardless of
  597. different machines' byte orders or structure layout conventions,
  598. by always converting them to a network standard called
  599. X.I "eXternal Data Representation"
  600. (XDR) before
  601. sending them over the wire.
  602. The process of converting from a particular machine representation
  603. to XDR format is called
  604. X.I serializing ,
  605. and the reverse process is called
  606. X.I deserializing .
  607. The type field parameters of
  608. X.I callrpc 
  609. and
  610. X.I registerrpc 
  611. can be a built-in procedure like
  612. X.I xdr_u_long 
  613. in the previous example, or a user supplied one.
  614. XDR has these built-in type routines:
  615. X.IX RPC "built-in routines"
  616. X.DS
  617. X.ft CW
  618. xdr_int()      xdr_u_int()      xdr_enum()
  619. xdr_long()     xdr_u_long()     xdr_bool()
  620. xdr_short()    xdr_u_short()    xdr_wrapstring()
  621. xdr_char()     xdr_u_char()
  622. X.DE
  623. Note that the routine
  624. X.I xdr_string
  625. exists, but cannot be used with 
  626. X.I callrpc 
  627. and
  628. X.I registerrpc ,
  629. which only pass two parameters to their XDR routines.
  630. X.I xdr_wrapstring 
  631. has only two parameters, and is thus OK.  It calls 
  632. X.I xdr_string .
  633. X.LP
  634. As an example of a user-defined type routine,
  635. if you wanted to send the structure
  636. X.DS
  637. X.ft CW
  638. struct simple {
  639.     int a;
  640.     short b;
  641. } simple;
  642. X.DE
  643. then you would call
  644. X.I callrpc
  645. as
  646. X.DS
  647. X.ft CW
  648. callrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
  649.         xdr_simple, &simple ...);
  650. X.DE
  651. where
  652. X.I xdr_simple
  653. is written as:
  654. X.ie t .DS
  655. X.el .DS L
  656. X.ft CW
  657. #include <rpc/rpc.h>
  658.  
  659. xdr_simple(xdrsp, simplep)
  660.     XDR *xdrsp;
  661.     struct simple *simplep;
  662. {
  663.     if (!xdr_int(xdrsp, &simplep->a))
  664.         return (0);
  665.     if (!xdr_short(xdrsp, &simplep->b))
  666.         return (0);
  667.     return (1);
  668. }
  669. X.DE
  670. X.LP
  671. An XDR routine returns nonzero (true in the sense of C) if it 
  672. completes successfully, and zero otherwise.
  673. A complete description of XDR is in the
  674. X.I "XDR Protocol Specification" 
  675. section of this manual, only few implementation examples are 
  676. given here.
  677. X.LP
  678. In addition to the built-in primitives,
  679. there are also the prefabricated building blocks:
  680. X.DS
  681. X.ft CW
  682. xdr_array()       xdr_bytes()     xdr_reference()
  683. xdr_vector()      xdr_union()     xdr_pointer()
  684. xdr_string()      xdr_opaque()
  685. X.DE
  686. To send a variable array of integers,
  687. you might package them up as a structure like this
  688. X.DS
  689. X.ft CW
  690. struct varintarr {
  691.     int *data;
  692.     int arrlnth;
  693. } arr;
  694. X.DE
  695. and make an RPC call such as
  696. X.DS
  697. X.ft CW
  698. callrpc(hostname, PROGNUM, VERSNUM, PROCNUM,
  699.         xdr_varintarr, &arr...);
  700. X.DE
  701. with
  702. X.I xdr_varintarr 
  703. defined as:
  704. X.ie t .DS
  705. X.el .DS L
  706. X.ft CW
  707. xdr_varintarr(xdrsp, arrp)
  708.     XDR *xdrsp;
  709.     struct varintarr *arrp;
  710. {
  711.     return (xdr_array(xdrsp, &arrp->data, &arrp->arrlnth, 
  712.         MAXLEN, sizeof(int), xdr_int));
  713. }
  714. X.DE
  715. This routine takes as parameters the XDR handle,
  716. a pointer to the array, a pointer to the size of the array,
  717. the maximum allowable array size,
  718. the size of each array element,
  719. and an XDR routine for handling each array element.
  720. X.KS
  721. X.LP
  722. If the size of the array is known in advance, one can use
  723. X.I xdr_vector ,
  724. which serializes fixed-length arrays.
  725. X.ie t .DS
  726. X.el .DS L
  727. X.ft CW
  728. int intarr[SIZE];
  729.  
  730. xdr_intarr(xdrsp, intarr)
  731.     XDR *xdrsp;
  732.     int intarr[];
  733. {
  734.     int i;
  735.  
  736.     return (xdr_vector(xdrsp, intarr, SIZE, sizeof(int),
  737.         xdr_int));
  738. }
  739. X.DE
  740. X.KE
  741. X.LP
  742. XDR always converts quantities to 4-byte multiples when deserializing.
  743. Thus, if either of the examples above involved characters
  744. instead of integers, each character would occupy 32 bits.
  745. That is the reason for the XDR routine
  746. X.I xdr_bytes
  747. which is like
  748. X.I xdr_array
  749. except that it packs characters;
  750. X.I xdr_bytes 
  751. has four parameters, similar to the first four parameters of
  752. X.I xdr_array .
  753. For null-terminated strings, there is also the
  754. X.I xdr_string
  755. routine, which is the same as
  756. X.I xdr_bytes 
  757. without the length parameter.
  758. On serializing it gets the string length from
  759. X.I strlen ,
  760. and on deserializing it creates a null-terminated string.
  761. X.LP
  762. Here is a final example that calls the previously written
  763. X.I xdr_simple 
  764. as well as the built-in functions
  765. X.I xdr_string 
  766. and
  767. X.I xdr_reference ,
  768. which chases pointers:
  769. X.ie t .DS
  770. X.el .DS L
  771. X.ft CW
  772. struct finalexample {
  773.     char *string;
  774.     struct simple *simplep;
  775. } finalexample;
  776.  
  777. xdr_finalexample(xdrsp, finalp)
  778.     XDR *xdrsp;
  779.     struct finalexample *finalp;
  780. {
  781.  
  782.     if (!xdr_string(xdrsp, &finalp->string, MAXSTRLEN))
  783.         return (0);
  784.     if (!xdr_reference(xdrsp, &finalp->simplep,
  785.       sizeof(struct simple), xdr_simple);
  786.         return (0);
  787.     return (1);
  788. }
  789. X.DE
  790. X.
  791. X.NH 1
  792. \&Lowest Layer of RPC
  793. X.IX "lowest layer of RPC"
  794. X.IX "RPC" "lowest layer"
  795. X.LP
  796. In the examples given so far,
  797. RPC takes care of many details automatically for you.
  798. In this section, we'll show you how you can change the defaults
  799. by using lower layers of the RPC library.
  800. It is assumed that you are familiar with sockets
  801. and the system calls for dealing with them.
  802. If not, consult the
  803. X.I "IPC Primer" 
  804. section of this manual.
  805. X.LP
  806. There are several occasions when you may need to use lower layers of 
  807. RPC.  First, you may need to use TCP, since the higher layer uses UDP, 
  808. which restricts RPC calls to 8K bytes of data.  Using TCP permits calls 
  809. to send long streams of data.  For an example, see the 
  810. \fITCP\fP 
  811. section below.  Second, you may want to allocate and free memory
  812. while serializing or deserializing with XDR routines.  There is no 
  813. call at the higher level to let you free memory explicitly.  For more 
  814. explanation, see the 
  815. \fIMemory Allocation with XDR\fP 
  816. section below.  Third, you may need to perform authentication on either 
  817. the client or server side, by supplying credentials or verifying them.  
  818. See the explanation in the 
  819. \fIAuthentication\fP 
  820. section below.
  821. X.
  822. X.NH 2
  823. \&More on the Server Side
  824. X.IX RPC "server side"
  825. X.LP
  826. The server for the
  827. X.I nusers 
  828. program shown below does the same thing as the one using
  829. X.I registerrpc 
  830. above, but is written using a lower layer of the RPC package:
  831. X.ie t .DS
  832. X.el .DS L
  833. X.ft CW
  834. #include <stdio.h>
  835. #include <rpc/rpc.h>
  836. #include <utmp.h>
  837. #include <rpcsvc/rusers.h>
  838.  
  839. main()
  840. {
  841.     SVCXPRT *transp;
  842.     int nuser();
  843.  
  844.     transp = svcudp_create(RPC_ANYSOCK);
  845.     if (transp == NULL){
  846.         fprintf(stderr, "can't create an RPC server\en");
  847.         exit(1);
  848.     }
  849.     pmap_unset(RUSERSPROG, RUSERSVERS);
  850.     if (!svc_register(transp, RUSERSPROG, RUSERSVERS,
  851.               nuser, IPPROTO_UDP)) {
  852.         fprintf(stderr, "can't register RUSER service\en");
  853.         exit(1);
  854.     }
  855.     svc_run();  /* \fINever returns\fP */
  856.     fprintf(stderr, "should never reach this point\en");
  857. }
  858.  
  859. nuser(rqstp, transp)
  860.     struct svc_req *rqstp;
  861.     SVCXPRT *transp;
  862. {
  863.     unsigned long nusers;
  864.  
  865.     switch (rqstp->rq_proc) {
  866.     case NULLPROC:
  867.         if (!svc_sendreply(transp, xdr_void, 0))
  868.             fprintf(stderr, "can't reply to RPC call\en");
  869.         return;
  870.     case RUSERSPROC_NUM:
  871. X.ft I
  872.         /*
  873.          * Code here to compute the number of users
  874.          * and put in variable \fInusers\fP
  875.          */
  876. X.ft CW
  877.         if (!svc_sendreply(transp, xdr_u_long, &nusers)) 
  878.             fprintf(stderr, "can't reply to RPC call\en");
  879.         return;
  880.     default:
  881.         svcerr_noproc(transp);
  882.         return;
  883.     }
  884. }
  885. X.DE
  886. X.LP
  887. First, the server gets a transport handle, which is used
  888. for receiving and replying to RPC messages.
  889. X.I registerrpc 
  890. uses
  891. X.I svcudp_create
  892. to get a UDP handle.
  893. If you require a more reliable protocol, call
  894. X.I svctcp_create
  895. instead.
  896. If the argument to
  897. X.I svcudp_create 
  898. is
  899. X.I RPC_ANYSOCK
  900. the RPC library creates a socket
  901. on which to receive and reply to RPC calls.  Otherwise,
  902. X.I svcudp_create 
  903. expects its argument to be a valid socket number.
  904. If you specify your own socket, it can be bound or unbound.
  905. If it is bound to a port by the user, the port numbers of
  906. X.I svcudp_create 
  907. and
  908. X.I clntcp_create
  909. (the low-level client routine) must match.
  910. X.LP
  911. If the user specifies the
  912. X.I RPC_ANYSOCK 
  913. argument, the RPC library routines will open sockets.
  914. Otherwise they will expect the user to do so.  The routines
  915. X.I svcudp_create 
  916. and 
  917. X.I clntudp_create
  918. will cause the RPC library routines to
  919. X.I bind 
  920. their socket if it is not bound already.
  921. X.LP
  922. A service may choose to register its port number with the
  923. local portmapper service.  This is done is done by specifying
  924. a non-zero protocol number in
  925. X.I svc_register .
  926. Incidently, a client can discover the server's port number by 
  927. consulting the portmapper on their server's machine.  This can 
  928. be done automatically by specifying a zero port number in 
  929. X.I clntudp_create 
  930. or
  931. X.I clntcp_create .
  932. X.LP
  933. After creating an
  934. X.I SVCXPRT ,
  935. the next step is to call
  936. X.I pmap_unset
  937. so that if the
  938. X.I nusers 
  939. server crashed earlier,
  940. any previous trace of it is erased before restarting.
  941. More precisely,
  942. X.I pmap_unset 
  943. erases the entry for
  944. X.I RUSERSPROG
  945. from the port mapper's tables.
  946. X.LP
  947. Finally, we associate the program number for
  948. X.I nusers 
  949. with the procedure
  950. X.I nuser .
  951. The final argument to
  952. X.I svc_register 
  953. is normally the protocol being used,
  954. which, in this case, is
  955. X.I IPPROTO_UDP
  956. Notice that unlike
  957. X.I registerrpc ,
  958. there are no XDR routines involved
  959. in the registration process.
  960. Also, registration is done on the program,
  961. rather than procedure, level.
  962. X.LP
  963. The user routine
  964. X.I nuser 
  965. must call and dispatch the appropriate XDR routines
  966. based on the procedure number.
  967. Note that
  968. two things are handled by
  969. X.I nuser 
  970. that
  971. X.I registerrpc 
  972. handles automatically.
  973. The first is that procedure
  974. X.I NULLPROC
  975. (currently zero) returns with no results.
  976. This can be used as a simple test
  977. for detecting if a remote program is running.
  978. Second, there is a check for invalid procedure numbers.
  979. If one is detected,
  980. X.I svcerr_noproc
  981. is called to handle the error.
  982. X.KS
  983. X.LP
  984. The user service routine serializes the results and returns
  985. them to the RPC caller via
  986. X.I svc_sendreply
  987. Its first parameter is the
  988. X.I SVCXPRT
  989. handle, the second is the XDR routine,
  990. and the third is a pointer to the data to be returned.
  991. Not illustrated above is how a server
  992. handles an RPC program that receives data.
  993. As an example, we can add a procedure
  994. X.I RUSERSPROC_BOOL
  995. which has an argument
  996. X.I nusers ,
  997. and returns
  998. X.I TRUE 
  999. or
  1000. X.I FALSE 
  1001. depending on whether there are nusers logged on.
  1002. It would look like this:
  1003. X.ie t .DS
  1004. X.el .DS L
  1005. X.ft CW
  1006. case RUSERSPROC_BOOL: {
  1007.     int bool;
  1008.     unsigned nuserquery;
  1009.  
  1010.     if (!svc_getargs(transp, xdr_u_int, &nuserquery) {
  1011.         svcerr_decode(transp);
  1012.         return;
  1013.     }
  1014. X.ft I
  1015.     /*
  1016.      * Code to set \fInusers\fP = number of users
  1017.      */
  1018. X.ft CW
  1019.     if (nuserquery == nusers)
  1020.         bool = TRUE;
  1021.     else
  1022.         bool = FALSE;
  1023.     if (!svc_sendreply(transp, xdr_bool, &bool)) {
  1024.          fprintf(stderr, "can't reply to RPC call\en");
  1025.          exit(1);
  1026.     }
  1027.     return;
  1028. }
  1029. X.DE
  1030. X.KE
  1031. X.LP
  1032. The relevant routine is
  1033. X.I svc_getargs
  1034. which takes an
  1035. X.I SVCXPRT
  1036. handle, the XDR routine,
  1037. and a pointer to where the input is to be placed as arguments.
  1038. X.
  1039. X.NH 2
  1040. \&Memory Allocation with XDR
  1041. X.IX "memory allocation with XDR"
  1042. X.IX "XDR memory allocation"
  1043. X.IX XDR "memory allocation"
  1044. X.LP
  1045. XDR routines not only do input and output,
  1046. they also do memory allocation.
  1047. This is why the second parameter of
  1048. X.I xdr_array
  1049. is a pointer to an array, rather than the array itself.
  1050. If it is
  1051. X.I NULL ,
  1052. then
  1053. X.I xdr_array
  1054. allocates space for the array and returns a pointer to it,
  1055. putting the size of the array in the third argument.
  1056. As an example, consider the following XDR routine
  1057. X.I xdr_chararr1
  1058. which deals with a fixed array of bytes with length
  1059. X.I SIZE
  1060. X.ie t .DS
  1061. X.el .DS L
  1062. X.ft CW
  1063. xdr_chararr1(xdrsp, chararr)
  1064.     XDR *xdrsp;
  1065.     char chararr[];
  1066. {
  1067.     char *p;
  1068.     int len;
  1069.  
  1070.     p = chararr;
  1071.     len = SIZE;
  1072.     return (xdr_bytes(xdrsp, &p, &len, SIZE));
  1073. }
  1074. X.DE
  1075. It might be called from a server like this,
  1076. X.ie t .DS
  1077. X.el .DS L
  1078. X.ft CW
  1079. char chararr[SIZE];
  1080.  
  1081. svc_getargs(transp, xdr_chararr1, chararr);
  1082. X.DE
  1083. space has already been allocated in
  1084. X.I chararr .
  1085. If you want XDR to do the allocation,
  1086. you would have to rewrite this routine in the following way:
  1087. X.ie t .DS
  1088. X.el .DS L
  1089. X.ft CW
  1090. xdr_chararr2(xdrsp, chararrp)
  1091.     XDR *xdrsp;
  1092.     char **chararrp;
  1093. {
  1094.     int len;
  1095.  
  1096.     len = SIZE;
  1097.     return (xdr_bytes(xdrsp, charrarrp, &len, SIZE));
  1098. }
  1099. X.DE
  1100. Then the RPC call might look like this:
  1101. X.ie t .DS
  1102. X.el .DS L
  1103. X.ft CW
  1104. char *arrptr;
  1105.  
  1106. arrptr = NULL;
  1107. svc_getargs(transp, xdr_chararr2, &arrptr);
  1108. X.ft I
  1109. /*
  1110.  * Use the result here
  1111.  */
  1112. X.ft CW
  1113. svc_freeargs(transp, xdr_chararr2, &arrptr);
  1114. X.DE
  1115. Note that, after being used, the character array can be freed with
  1116. X.I svc_freeargs
  1117. X.I svc_freeargs 
  1118. will not attempt to free any memory if the variable indicating it 
  1119. is NULL.  For example, in the the routine 
  1120. X.I xdr_finalexample ,
  1121. given earlier, if
  1122. X.I finalp->string 
  1123. was NULL, then it would not be freed.  The same is true for 
  1124. X.I finalp->simplep .
  1125. X.LP
  1126. To summarize, each XDR routine is responsible
  1127. for serializing, deserializing, and freeing memory.
  1128. When an XDR routine is called from
  1129. X.I callrpc
  1130. the serializing part is used.
  1131. When called from
  1132. X.I svc_getargs
  1133. the deserializer is used.
  1134. And when called from
  1135. X.I svc_freeargs
  1136. the memory deallocator is used.  When building simple examples like those
  1137. in this section, a user doesn't have to worry about the three modes.  See
  1138. the 
  1139. \fIeXternal Data Representation: Sun Technical Notes\fP
  1140. chapter for examples of more sophisticated XDR routines that determine 
  1141. which of the three modes they are in and adjust their behavior accordingly.
  1142. X.
  1143. X.KS
  1144. X.NH 2
  1145. \&The Calling Side
  1146. X.IX RPC "calling side"
  1147. X.LP
  1148. When you use
  1149. X.I callrpc
  1150. you have no control over the RPC delivery
  1151. mechanism or the socket used to transport the data.
  1152. To illustrate the layer of RPC that lets you adjust these
  1153. parameters, consider the following code to call the
  1154. X.I nusers
  1155. service:
  1156. X.ie t .DS
  1157. X.el .DS L
  1158. X.ft CW
  1159. X.vs 11
  1160. #include <stdio.h>
  1161. #include <rpc/rpc.h>
  1162. #include <utmp.h>
  1163. #include <rpcsvc/rusers.h>
  1164. #include <sys/socket.h>
  1165. #include <sys/time.h>
  1166. #include <netdb.h>
  1167.  
  1168. main(argc, argv)
  1169.     int argc;
  1170.     char **argv;
  1171. {
  1172.     struct hostent *hp;
  1173.     struct timeval pertry_timeout, total_timeout;
  1174.     struct sockaddr_in server_addr;
  1175.     int sock = RPC_ANYSOCK;
  1176.     register CLIENT *client;
  1177.     enum clnt_stat clnt_stat;
  1178.     unsigned long nusers;
  1179.  
  1180.     if (argc < 2) {
  1181.         fprintf(stderr, "usage: nusers hostname\en");
  1182.         exit(-1);
  1183.     }
  1184.     if ((hp = gethostbyname(argv[1])) == NULL) {
  1185.         fprintf(stderr, "can't get addr for %s\en",argv[1]);
  1186.         exit(-1);
  1187.     }
  1188.     pertry_timeout.tv_sec = 3;
  1189.     pertry_timeout.tv_usec = 0;
  1190.     bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
  1191.         hp->h_length);
  1192.     server_addr.sin_family = AF_INET;
  1193.     server_addr.sin_port =  0;
  1194.     if ((client = clntudp_create(&server_addr, RUSERSPROG,
  1195.       RUSERSVERS, pertry_timeout, &sock)) == NULL) {
  1196.         clnt_pcreateerror("clntudp_create");
  1197.         exit(-1);
  1198.     }
  1199.     total_timeout.tv_sec = 20;
  1200.     total_timeout.tv_usec = 0;
  1201.     clnt_stat = clnt_call(client, RUSERSPROC_NUM, xdr_void,
  1202.         0, xdr_u_long, &nusers, total_timeout);
  1203.     if (clnt_stat != RPC_SUCCESS) {
  1204.         clnt_perror(client, "rpc");
  1205.         exit(-1);
  1206.     }
  1207.     clnt_destroy(client);
  1208.     close(sock);
  1209. }
  1210. X.vs
  1211. X.DE
  1212. X.KE
  1213. The low-level version of
  1214. X.I callrpc
  1215. is
  1216. X.I clnt_call
  1217. which takes a
  1218. X.I CLIENT
  1219. pointer rather than a host name.  The parameters to
  1220. X.I clnt_call 
  1221. are a
  1222. X.I CLIENT 
  1223. pointer, the procedure number,
  1224. the XDR routine for serializing the argument,
  1225. a pointer to the argument,
  1226. the XDR routine for deserializing the return value,
  1227. a pointer to where the return value will be placed,
  1228. and the time in seconds to wait for a reply.
  1229. X.LP
  1230. The
  1231. X.I CLIENT 
  1232. pointer is encoded with the transport mechanism.
  1233. X.I callrpc
  1234. uses UDP, thus it calls
  1235. X.I clntudp_create 
  1236. to get a
  1237. X.I CLIENT 
  1238. pointer.  To get TCP (Transmission Control Protocol), you would use
  1239. X.I clnttcp_create
  1240. X.LP
  1241. The parameters to
  1242. X.I clntudp_create 
  1243. are the server address, the program number, the version number,
  1244. a timeout value (between tries), and a pointer to a socket.
  1245. The final argument to
  1246. X.I clnt_call 
  1247. is the total time to wait for a response.
  1248. Thus, the number of tries is the
  1249. X.I clnt_call 
  1250. timeout divided by the
  1251. X.I clntudp_create 
  1252. timeout.
  1253. X.LP
  1254. There is one thing to note when using the
  1255. X.I clnt_destroy
  1256. call.
  1257. It deallocates any space associated with the
  1258. X.I CLIENT 
  1259. handle, but it does not close the socket associated with it,
  1260. which was passed as an argument to
  1261. X.I clntudp_create .
  1262. This makes it possible, in cases where there are multiple 
  1263. client handles using the same socket, to destroy one handle
  1264. without closing the socket that other handles are using.
  1265. X.LP
  1266. To make a stream connection, the call to
  1267. X.I clntudp_create 
  1268. is replaced with a call to
  1269. X.I clnttcp_create .
  1270. X.DS
  1271. X.ft CW
  1272. clnttcp_create(&server_addr, prognum, versnum, &sock,
  1273.                inputsize, outputsize);
  1274. X.DE
  1275. There is no timeout argument; instead, the receive and send buffer
  1276. sizes must be specified.  When the
  1277. X.I clnttcp_create 
  1278. call is made, a TCP connection is established.
  1279. All RPC calls using that
  1280. X.I CLIENT 
  1281. handle would use this connection.
  1282. The server side of an RPC call using TCP has
  1283. X.I svcudp_create
  1284. replaced by
  1285. X.I svctcp_create
  1286. X.DS
  1287. X.ft CW
  1288. transp = svctcp_create(RPC_ANYSOCK, 0, 0);
  1289. X.DE
  1290. The last two arguments to 
  1291. X.I svctcp_create 
  1292. are send and receive sizes respectively.  If `0' is specified for 
  1293. either of these, the system chooses a reasonable default.
  1294. X.
  1295. X.KS
  1296. X.NH 1
  1297. \&Other RPC Features
  1298. X.IX "RPC" "miscellaneous features"
  1299. X.IX "miscellaneous RPC features"
  1300. X.LP
  1301. This section discusses some other aspects of RPC
  1302. that are occasionally useful.
  1303. X.
  1304. X.NH 2
  1305. \&Select on the Server Side
  1306. X.IX RPC select "" \fIselect\fP
  1307. X.IX "select on the server side" "" "\fIselect\fP on the server side"
  1308. X.LP
  1309. Suppose a process is processing RPC requests
  1310. while performing some other activity.
  1311. If the other activity involves periodically updating a data structure,
  1312. the process can set an alarm signal before calling
  1313. X.I svc_run
  1314. But if the other activity
  1315. involves waiting on a a file descriptor, the
  1316. X.I svc_run
  1317. call won't work.
  1318. The code for
  1319. X.I svc_run
  1320. is as follows:
  1321. X.ie t .DS
  1322. X.el .DS L
  1323. X.ft CW
  1324. X.vs 11
  1325. void
  1326. svc_run()
  1327. {
  1328.     fd_set readfds;
  1329.     int dtbsz = getdtablesize();
  1330.  
  1331.     for (;;) {
  1332.         readfds = svc_fds;
  1333.         switch (select(dtbsz, &readfds, NULL,NULL,NULL)) {
  1334.  
  1335.         case -1:
  1336.             if (errno == EINTR)
  1337.                 continue;
  1338.             perror("select");
  1339.             return;
  1340.         case 0:
  1341.             break;
  1342.         default:
  1343.             svc_getreqset(&readfds);
  1344.         }
  1345.     }
  1346. }
  1347. X.vs
  1348. X.DE
  1349. X.KE
  1350. X.LP
  1351. You can bypass
  1352. X.I svc_run
  1353. and call
  1354. X.I svc_getreqset
  1355. yourself.
  1356. All you need to know are the file descriptors
  1357. of the socket(s) associated with the programs you are waiting on.
  1358. Thus you can have your own
  1359. X.I select
  1360. that waits on both the RPC socket,
  1361. and your own descriptors.  Note that
  1362. X.I svc_fds 
  1363. is a bit mask of all the file descriptors that RPC is using for 
  1364. services.  It can change everytime that
  1365. X.I any
  1366. RPC library routine is called, because descriptors are constantly 
  1367. being opened and closed, for example for TCP connections.
  1368. X.
  1369. X.NH 2
  1370. \&Broadcast RPC
  1371. X.IX "broadcast RPC"
  1372. X.IX RPC "broadcast"
  1373. X.LP
  1374. The
  1375. X.I portmapper
  1376. is a daemon that converts RPC program numbers
  1377. into DARPA protocol port numbers; see the
  1378. X.I portmap 
  1379. man page.  You can't do broadcast RPC without the portmapper.
  1380. Here are the main differences between
  1381. broadcast RPC and normal RPC calls:
  1382. X.IP  1.
  1383. Normal RPC expects one answer, whereas
  1384. broadcast RPC expects many answers
  1385. (one or more answer from each responding machine).
  1386. X.IP  2.
  1387. Broadcast RPC can only be supported by packet-oriented (connectionless)
  1388. transport protocols like UPD/IP.
  1389. X.IP  3.
  1390. The implementation of broadcast RPC
  1391. treats all unsuccessful responses as garbage by filtering them out.
  1392. Thus, if there is a version mismatch between the
  1393. broadcaster and a remote service,
  1394. the user of broadcast RPC never knows.
  1395. X.IP  4.
  1396. All broadcast messages are sent to the portmap port.
  1397. Thus, only services that register themselves with their portmapper
  1398. are accessible via the broadcast RPC mechanism.
  1399. X.
  1400. X.NH 3
  1401. \&Broadcast RPC Synopsis
  1402. X.IX "RPC" "broadcast synopsis"
  1403. X.ie t .DS
  1404. X.el .DS L
  1405. X.ft CW
  1406. #include <rpc/pmap_clnt.h>
  1407.     . . .
  1408. enum clnt_stat    clnt_stat;
  1409.     . . .
  1410. clnt_stat = clnt_broadcast(prognum, versnum, procnum,
  1411.   inproc, in, outproc, out, eachresult)
  1412.     u_long    prognum;        /* \fIprogram number\fP */
  1413.     u_long    versnum;        /* \fIversion number\fP */
  1414.     u_long    procnum;        /* \fIprocedure number\fP */
  1415.     xdrproc_t inproc;         /* \fIxdr routine for args\fP */
  1416.     caddr_t   in;             /* \fIpointer to args\fP */
  1417.     xdrproc_t outproc;        /* \fIxdr routine for results\fP */
  1418.     caddr_t   out;            /* \fIpointer to results\fP */
  1419.     bool_t    (*eachresult)();/* \fIcall with each result gotten\fP */
  1420. X.DE
  1421. X.LP
  1422. The procedure
  1423. X.I eachresult
  1424. is called each time a valid result is obtained.
  1425. It returns a boolean that indicates
  1426. whether or not the user wants more responses.
  1427. X.ie t .DS
  1428. X.el .DS L
  1429. X.ft CW
  1430. bool_t done;
  1431.     . . . 
  1432. done = eachresult(resultsp, raddr)
  1433.     caddr_t resultsp;
  1434.     struct sockaddr_in *raddr; /* \fIAddr of responding machine\fP */
  1435. X.DE
  1436. If
  1437. X.I done
  1438. is
  1439. X.I TRUE ,
  1440. then broadcasting stops and
  1441. X.I clnt_broadcast
  1442. returns successfully.
  1443. Otherwise, the routine waits for another response.
  1444. The request is rebroadcast
  1445. after a few seconds of waiting.
  1446. If no responses come back,
  1447. the routine returns with
  1448. X.I RPC_TIMEDOUT
  1449. X.
  1450. X.NH 2
  1451. \&Batching
  1452. X.IX "batching"
  1453. X.IX RPC "batching"
  1454. X.LP
  1455. The RPC architecture is designed so that clients send a call message,
  1456. and wait for servers to reply that the call succeeded.
  1457. This implies that clients do not compute
  1458. while servers are processing a call.
  1459. This is inefficient if the client does not want or need
  1460. an acknowledgement for every message sent.
  1461. It is possible for clients to continue computing
  1462. while waiting for a response,
  1463. using RPC batch facilities.
  1464. X.LP
  1465. RPC messages can be placed in a ``pipeline'' of calls
  1466. to a desired server; this is called batching.
  1467. Batching assumes that:
  1468. 1) each RPC call in the pipeline requires no response from the server,
  1469. and the server does not send a response message; and
  1470. 2) the pipeline of calls is transported on a reliable
  1471. byte stream transport such as TCP/IP.
  1472. Since the server does not respond to every call,
  1473. the client can generate new calls in parallel
  1474. with the server executing previous calls.
  1475. Furthermore, the TCP/IP implementation can buffer up
  1476. many call messages, and send them to the server in one
  1477. X.I write
  1478. system call.  This overlapped execution
  1479. greatly decreases the interprocess communication overhead of
  1480. the client and server processes,
  1481. and the total elapsed time of a series of calls.
  1482. X.LP
  1483. Since the batched calls are buffered,
  1484. the client should eventually do a legitimate call
  1485. in order to flush the pipeline.
  1486. X.LP
  1487. A contrived example of batching follows.
  1488. Assume a string rendering service (like a window system)
  1489. has two similar calls: one renders a string and returns void results,
  1490. while the other renders a string and remains silent.
  1491. The service (using the TCP/IP transport) may look like:
  1492. X.ie t .DS
  1493. X.el .DS L
  1494. X.ft CW
  1495. #include <stdio.h>
  1496. #include <rpc/rpc.h>
  1497. #include <suntool/windows.h>
  1498.  
  1499. void windowdispatch();
  1500.  
  1501. main()
  1502. {
  1503.     SVCXPRT *transp;
  1504.  
  1505.     transp = svctcp_create(RPC_ANYSOCK, 0, 0);
  1506.     if (transp == NULL){
  1507.         fprintf(stderr, "can't create an RPC server\en");
  1508.         exit(1);
  1509.     }
  1510.     pmap_unset(WINDOWPROG, WINDOWVERS);
  1511.     if (!svc_register(transp, WINDOWPROG, WINDOWVERS,
  1512.       windowdispatch, IPPROTO_TCP)) {
  1513.         fprintf(stderr, "can't register WINDOW service\en");
  1514.         exit(1);
  1515.     }
  1516.     svc_run();  /* \fINever returns\fP */
  1517.     fprintf(stderr, "should never reach this point\en");
  1518. }
  1519.  
  1520. void
  1521. windowdispatch(rqstp, transp)
  1522.     struct svc_req *rqstp;
  1523.     SVCXPRT *transp;
  1524. {
  1525.     char *s = NULL;
  1526.  
  1527.     switch (rqstp->rq_proc) {
  1528.     case NULLPROC:
  1529.         if (!svc_sendreply(transp, xdr_void, 0)) 
  1530.             fprintf(stderr, "can't reply to RPC call\en");
  1531.         return;
  1532.     case RENDERSTRING:
  1533.         if (!svc_getargs(transp, xdr_wrapstring, &s)) {
  1534.             fprintf(stderr, "can't decode arguments\en");
  1535. X.ft I
  1536.             /*
  1537.              * Tell caller he screwed up
  1538.              */
  1539. X.ft CW
  1540.             svcerr_decode(transp);
  1541.             break;
  1542.         }
  1543. X.ft I
  1544.         /*
  1545.          * Call here to render the string \fIs\fP
  1546.          */
  1547. X.ft CW
  1548.         if (!svc_sendreply(transp, xdr_void, NULL)) 
  1549.             fprintf(stderr, "can't reply to RPC call\en");
  1550.         break;
  1551.     case RENDERSTRING_BATCHED:
  1552.         if (!svc_getargs(transp, xdr_wrapstring, &s)) {
  1553.             fprintf(stderr, "can't decode arguments\en");
  1554. X.ft I
  1555.             /*
  1556.              * We are silent in the face of protocol errors
  1557.              */
  1558. X.ft CW
  1559.             break;
  1560.         }
  1561. X.ft I
  1562.         /*
  1563.          * Call here to render string s, but send no reply!
  1564.          */
  1565. X.ft CW
  1566.         break;
  1567.     default:
  1568.         svcerr_noproc(transp);
  1569.         return;
  1570.     }
  1571. X.ft I
  1572.     /*
  1573.      * Now free string allocated while decoding arguments
  1574.      */
  1575. X.ft CW
  1576.     svc_freeargs(transp, xdr_wrapstring, &s);
  1577. }
  1578. X.DE
  1579. Of course the service could have one procedure
  1580. that takes the string and a boolean
  1581. to indicate whether or not the procedure should respond.
  1582. X.LP
  1583. In order for a client to take advantage of batching,
  1584. the client must perform RPC calls on a TCP-based transport
  1585. and the actual calls must have the following attributes:
  1586. 1) the result's XDR routine must be zero
  1587. X.I NULL ),
  1588. and 2) the RPC call's timeout must be zero.
  1589. X.KS
  1590. X.LP
  1591. Here is an example of a client that uses batching
  1592. to render a bunch of strings;
  1593. the batching is flushed when the client gets a null string:
  1594. X.ie t .DS
  1595. X.el .DS L
  1596. X.ft CW
  1597. X.vs 11
  1598. #include <stdio.h>
  1599. #include <rpc/rpc.h>
  1600. #include <sys/socket.h>
  1601. #include <sys/time.h>
  1602. #include <netdb.h>
  1603. #include <suntool/windows.h>
  1604.  
  1605. main(argc, argv)
  1606.     int argc;
  1607.     char **argv;
  1608. {
  1609.     struct hostent *hp;
  1610.     struct timeval pertry_timeout, total_timeout;
  1611.     struct sockaddr_in server_addr;
  1612.     int sock = RPC_ANYSOCK;
  1613.     register CLIENT *client;
  1614.     enum clnt_stat clnt_stat;
  1615.     char buf[1000], *s = buf;
  1616.  
  1617.     if ((client = clnttcp_create(&server_addr,
  1618.       WINDOWPROG, WINDOWVERS, &sock, 0, 0)) == NULL) {
  1619.         perror("clnttcp_create");
  1620.         exit(-1);
  1621.     }
  1622.     total_timeout.tv_sec = 0;
  1623.     total_timeout.tv_usec = 0;
  1624.     while (scanf("%s", s) != EOF) {
  1625.         clnt_stat = clnt_call(client, RENDERSTRING_BATCHED,
  1626.             xdr_wrapstring, &s, NULL, NULL, total_timeout);
  1627.         if (clnt_stat != RPC_SUCCESS) {
  1628.             clnt_perror(client, "batched rpc");
  1629.             exit(-1);
  1630.         }
  1631.     }
  1632.  
  1633.     /* \fINow flush the pipeline\fP */
  1634.  
  1635.     total_timeout.tv_sec = 20;
  1636.     clnt_stat = clnt_call(client, NULLPROC, xdr_void, NULL,
  1637.         xdr_void, NULL, total_timeout);
  1638.     if (clnt_stat != RPC_SUCCESS) {
  1639.         clnt_perror(client, "rpc");
  1640.         exit(-1);
  1641.     }
  1642.     clnt_destroy(client);
  1643. }
  1644. X.vs
  1645. X.DE
  1646. X.KE
  1647. Since the server sends no message,
  1648. the clients cannot be notified of any of the failures that may occur.
  1649. Therefore, clients are on their own when it comes to handling errors.
  1650. X.LP
  1651. The above example was completed to render
  1652. all of the (2000) lines in the file
  1653. X.I /etc/termcap .
  1654. The rendering service did nothing but throw the lines away.
  1655. The example was run in the following four configurations:
  1656. 1) machine to itself, regular RPC;
  1657. 2) machine to itself, batched RPC;
  1658. 3) machine to another, regular RPC; and
  1659. 4) machine to another, batched RPC.
  1660. The results are as follows:
  1661. 1) 50 seconds;
  1662. 2) 16 seconds;
  1663. 3) 52 seconds;
  1664. 4) 10 seconds.
  1665. Running
  1666. X.I fscanf
  1667. on
  1668. X.I /etc/termcap 
  1669. only requires six seconds.
  1670. These timings show the advantage of protocols
  1671. that allow for overlapped execution,
  1672. though these protocols are often hard to design.
  1673. X.
  1674. X.NH 2
  1675. \&Authentication
  1676. X.IX "authentication"
  1677. X.IX "RPC" "authentication"
  1678. X.LP
  1679. In the examples presented so far,
  1680. the caller never identified itself to the server,
  1681. and the server never required an ID from the caller.
  1682. Clearly, some network services, such as a network filesystem,
  1683. require stronger security than what has been presented so far.
  1684. X.LP
  1685. In reality, every RPC call is authenticated by
  1686. the RPC package on the server, and similarly,
  1687. the RPC client package generates and sends authentication parameters.
  1688. Just as different transports (TCP/IP or UDP/IP)
  1689. can be used when creating RPC clients and servers,
  1690. different forms of authentication can be associated with RPC clients;
  1691. the default authentication type used as a default is type
  1692. X.I none .
  1693. X.LP
  1694. The authentication subsystem of the RPC package is open ended.
  1695. That is, numerous types of authentication are easy to support.
  1696. X.NH 3
  1697. \&UNIX Authentication
  1698. X.IX "UNIX Authentication"
  1699. X.IP "\fIThe Client Side\fP"
  1700. X.LP
  1701. When a caller creates a new RPC client handle as in:
  1702. X.DS
  1703. X.ft CW
  1704. clnt = clntudp_create(address, prognum, versnum,
  1705.               wait, sockp)
  1706. X.DE
  1707. the appropriate transport instance defaults
  1708. the associate authentication handle to be
  1709. X.DS
  1710. X.ft CW
  1711. clnt->cl_auth = authnone_create();
  1712. X.DE
  1713. The RPC client can choose to use
  1714. X.I UNIX
  1715. style authentication by setting
  1716. X.I clnt\->cl_auth
  1717. after creating the RPC client handle:
  1718. X.DS
  1719. X.ft CW
  1720. clnt->cl_auth = authunix_create_default();
  1721. X.DE
  1722. This causes each RPC call associated with
  1723. X.I clnt
  1724. to carry with it the following authentication credentials structure:
  1725. X.ie t .DS
  1726. X.el .DS L
  1727. X.ft I
  1728. /*
  1729.  * UNIX style credentials.
  1730.  */
  1731. X.ft CW
  1732. struct authunix_parms {
  1733.     u_long  aup_time;       /* \fIcredentials creation time\fP */
  1734.     char    *aup_machname;  /* \fIhost name where client is\fP */
  1735.     int     aup_uid;        /* \fIclient's UNIX effective uid\fP */
  1736.     int     aup_gid;        /* \fIclient's current group id\fP */
  1737.     u_int   aup_len;        /* \fIelement length of aup_gids\fP */
  1738.     int     *aup_gids;      /* \fIarray of groups user is in\fP */
  1739. };
  1740. X.DE
  1741. These fields are set by
  1742. X.I authunix_create_default
  1743. by invoking the appropriate system calls.
  1744. Since the RPC user created this new style of authentication,
  1745. the user is responsible for destroying it with:
  1746. X.DS
  1747. X.ft CW
  1748. auth_destroy(clnt->cl_auth);
  1749. X.DE
  1750. This should be done in all cases, to conserve memory.
  1751. X.sp
  1752. X.IP "\fIThe Server Side\fP"
  1753. X.LP
  1754. Service implementors have a harder time dealing with authentication issues
  1755. since the RPC package passes the service dispatch routine a request
  1756. that has an arbitrary authentication style associated with it.
  1757. Consider the fields of a request handle passed to a service dispatch routine:
  1758. X.ie t .DS
  1759. X.el .DS L
  1760. X.ft I
  1761. /*
  1762.  * An RPC Service request
  1763.  */
  1764. X.ft CW
  1765. struct svc_req {
  1766.     u_long    rq_prog;        /* \fIservice program number\fP */
  1767.     u_long    rq_vers;        /* \fIservice protocol vers num\fP */
  1768.     u_long    rq_proc;        /* \fIdesired procedure number\fP */
  1769.     struct opaque_auth rq_cred; /* \fIraw credentials from wire\fP */
  1770.     caddr_t   rq_clntcred;  /* \fIcredentials (read only)\fP */
  1771. };
  1772. X.DE
  1773. The
  1774. X.I rq_cred
  1775. is mostly opaque, except for one field of interest:
  1776. the style or flavor of authentication credentials:
  1777. X.ie t .DS
  1778. X.el .DS L
  1779. X.ft I
  1780. /*
  1781.  * Authentication info.  Mostly opaque to the programmer.
  1782.  */
  1783. X.ft CW
  1784. struct opaque_auth {
  1785.     enum_t  oa_flavor;  /* \fIstyle of credentials\fP */
  1786.     caddr_t oa_base;    /* \fIaddress of more auth stuff\fP */
  1787.     u_int   oa_length;  /* \fInot to exceed \fIMAX_AUTH_BYTES */
  1788. };
  1789. X.DE
  1790. X.IX RPC guarantees
  1791. The RPC package guarantees the following
  1792. to the service dispatch routine:
  1793. X.IP  1.
  1794. That the request's
  1795. X.I rq_cred
  1796. is well formed.  Thus the service implementor may inspect the request's
  1797. X.I rq_cred.oa_flavor
  1798. to determine which style of authentication the caller used.
  1799. The service implementor may also wish to inspect the other fields of
  1800. X.I rq_cred
  1801. if the style is not one of the styles supported by the RPC package.
  1802. X.IP  2.
  1803. That the request's
  1804. X.I rq_clntcred
  1805. field is either
  1806. X.I NULL 
  1807. or points to a well formed structure
  1808. that corresponds to a supported style of authentication credentials.
  1809. Remember that only
  1810. X.I unix
  1811. style is currently supported, so (currently)
  1812. X.I rq_clntcred
  1813. could be cast to a pointer to an
  1814. X.I authunix_parms
  1815. structure.  If
  1816. X.I rq_clntcred
  1817. is
  1818. X.I NULL ,
  1819. the service implementor may wish to inspect the other (opaque) fields of
  1820. X.I rq_cred
  1821. in case the service knows about a new type of authentication
  1822. that the RPC package does not know about.
  1823. X.LP
  1824. Our remote users service example can be extended so that
  1825. it computes results for all users except UID 16:
  1826. X.ie t .DS
  1827. X.el .DS L
  1828. X.ft CW
  1829. X.vs 11
  1830. nuser(rqstp, transp)
  1831.     struct svc_req *rqstp;
  1832.     SVCXPRT *transp;
  1833. {
  1834.     struct authunix_parms *unix_cred;
  1835.     int uid;
  1836.     unsigned long nusers;
  1837.  
  1838. X.ft I
  1839.     /*
  1840.      * we don't care about authentication for null proc
  1841.      */
  1842. X.ft CW
  1843.     if (rqstp->rq_proc == NULLPROC) {
  1844.         if (!svc_sendreply(transp, xdr_void, 0)) {
  1845.             fprintf(stderr, "can't reply to RPC call\en");
  1846.             exit(1);
  1847.          }
  1848.          return;
  1849.     }
  1850. X.ft I
  1851.     /*
  1852.      * now get the uid
  1853.      */
  1854. X.ft CW
  1855.     switch (rqstp->rq_cred.oa_flavor) {
  1856.     case AUTH_UNIX:
  1857.         unix_cred = 
  1858.             (struct authunix_parms *)rqstp->rq_clntcred;
  1859.         uid = unix_cred->aup_uid;
  1860.         break;
  1861.     case AUTH_NULL:
  1862.     default:
  1863.         svcerr_weakauth(transp);
  1864.         return;
  1865.     }
  1866.     switch (rqstp->rq_proc) {
  1867.     case RUSERSPROC_NUM:
  1868. X.ft I
  1869.         /*
  1870.          * make sure caller is allowed to call this proc
  1871.          */
  1872. X.ft CW
  1873.         if (uid == 16) {
  1874.             svcerr_systemerr(transp);
  1875.             return;
  1876.         }
  1877. X.ft I
  1878.         /*
  1879.          * code here to compute the number of users
  1880.          * and put in variable nusers
  1881.          */
  1882. X.ft CW
  1883.         if (!svc_sendreply(transp, xdr_u_long, &nusers)) {
  1884.             fprintf(stderr, "can't reply to RPC call\en");
  1885.             exit(1);
  1886.         }
  1887.         return;
  1888.     default:
  1889.         svcerr_noproc(transp);
  1890.         return;
  1891.     }
  1892. }
  1893. X.vs
  1894. X.DE
  1895. A few things should be noted here.
  1896. First, it is customary not to check
  1897. the authentication parameters associated with the
  1898. X.I NULLPROC
  1899. (procedure number zero).
  1900. Second, if the authentication parameter's type is not suitable
  1901. for your service, you should call
  1902. X.I svcerr_weakauth
  1903. And finally, the service protocol itself should return status
  1904. for access denied; in the case of our example, the protocol
  1905. does not have such a status, so we call the service primitive
  1906. X.I svcerr_systemerr
  1907. instead.
  1908. X.LP
  1909. The last point underscores the relation between
  1910. the RPC authentication package and the services;
  1911. RPC deals only with 
  1912. X.I authentication 
  1913. and not with individual services' 
  1914. X.I "access control" .
  1915. The services themselves must implement their own access control policies
  1916. and reflect these policies as return statuses in their protocols.
  1917. X.NH 2
  1918. \&Using Inetd
  1919. X.IX "using inetd" "" "using \&\fIinetd\fP"
  1920. X.LP
  1921. An RPC server can be started from
  1922. X.I inetd
  1923. The only difference from the usual code is that the service
  1924. creation routine should be called in the following form:
  1925. X.ie t .DS
  1926. X.el .DS L
  1927. X.ft CW
  1928. transp = svcudp_create(0);     /* \fIFor UDP\fP */
  1929. transp = svctcp_create(0,0,0); /* \fIFor listener TCP sockets\fP */
  1930. transp = svcfd_create(0,0,0);  /* \fIFor connected TCP sockets\fP */
  1931. X.DE
  1932. since
  1933. X.I inet
  1934. passes a socket as file descriptor 0.
  1935. Also,
  1936. X.I svc_register
  1937. should be called as
  1938. X.ie t .DS
  1939. X.el .DS L
  1940. X.ft CW
  1941. svc_register(transp, PROGNUM, VERSNUM, service, 0);
  1942. X.DE
  1943. with the final flag as 0,
  1944. since the program would already be registered by
  1945. X.I inetd
  1946. Remember that if you want to exit
  1947. from the server process and return control to
  1948. X.I inet
  1949. you need to explicitly exit, since
  1950. X.I svc_run
  1951. never returns.
  1952. X.LP
  1953. The format of entries in 
  1954. X.I /etc/inetd.conf 
  1955. for RPC services is in one of the following two forms:
  1956. X.ie t .DS
  1957. X.el .DS L
  1958. X.ft CW
  1959. p_name/version dgram  rpc/udp wait/nowait user server args
  1960. p_name/version stream rpc/tcp wait/nowait user server args
  1961. X.DE
  1962. where
  1963. X.I p_name
  1964. is the symbolic name of the program as it appears in
  1965. X.I rpc (5),
  1966. X.I server
  1967. is the C code implementing the server,
  1968. and
  1969. X.I program
  1970. and
  1971. X.I version
  1972. are the program and version numbers of the service.
  1973. For more information, see
  1974. X.I inetd.conf (5).
  1975. X.LP
  1976. If the same program handles multiple versions,
  1977. then the version number can be a range,
  1978. as in this example:
  1979. X.ie t .DS
  1980. X.el .DS L
  1981. X.ft CW
  1982. rstatd/1-2 dgram rpc/udp wait root /usr/etc/rpc.rstatd
  1983. X.DE
  1984. X.NH 1
  1985. \&More Examples
  1986. X.sp 1
  1987. X.NH 2
  1988. \&Versions
  1989. X.IX "versions"
  1990. X.IX "RPC" "versions"
  1991. X.LP
  1992. By convention, the first version number of program
  1993. X.I PROG
  1994. is
  1995. X.I PROGVERS_ORIG
  1996. and the most recent version is
  1997. X.I PROGVERS
  1998. Suppose there is a new version of the
  1999. X.I user
  2000. program that returns an
  2001. X.I "unsigned
  2002. rather than a
  2003. X.I long.
  2004. If we name this version
  2005. X.I RUSERSVERS_SHORT
  2006. then a server that wants to support both versions
  2007. would do a double register.
  2008. X.ie t .DS
  2009. X.el .DS L
  2010. X.ft CW
  2011. if (!svc_register(transp, RUSERSPROG, RUSERSVERS_ORIG,
  2012.   nuser, IPPROTO_TCP)) {
  2013.     fprintf(stderr, "can't register RUSER service\en");
  2014.     exit(1);
  2015. }
  2016. if (!svc_register(transp, RUSERSPROG, RUSERSVERS_SHORT,
  2017.   nuser, IPPROTO_TCP)) {
  2018.     fprintf(stderr, "can't register RUSER service\en");
  2019.     exit(1);
  2020. }
  2021. X.DE
  2022. Both versions can be handled by the same C procedure:
  2023. X.ie t .DS
  2024. X.el .DS L
  2025. X.ft CW
  2026. X.vs 11
  2027. nuser(rqstp, transp)
  2028.     struct svc_req *rqstp;
  2029.     SVCXPRT *transp;
  2030. {
  2031.     unsigned long nusers;
  2032.     unsigned short nusers2;
  2033.  
  2034.     switch (rqstp->rq_proc) {
  2035.     case NULLPROC:
  2036.         if (!svc_sendreply(transp, xdr_void, 0)) {
  2037.             fprintf(stderr, "can't reply to RPC call\en");
  2038.             exit(1);
  2039.         }
  2040.         return;
  2041.     case RUSERSPROC_NUM:
  2042. X.ft I
  2043.         /*
  2044.          * code here to compute the number of users
  2045.          * and put in variable nusers
  2046.          */
  2047. X.ft CW
  2048.         nusers2 = nusers;
  2049.         switch (rqstp->rq_vers) {
  2050.         case RUSERSVERS_ORIG:
  2051.             if (!svc_sendreply(transp, xdr_u_long, &nusers)) {
  2052.                 fprintf(stderr, "can't reply to RPC call\en");
  2053.             }
  2054.             break;
  2055.         case RUSERSVERS_SHORT:
  2056.             if (!svc_sendreply(transp, xdr_u_short, &nusers2)) {
  2057.                 fprintf(stderr, "can't reply to RPC call\en");
  2058.             }
  2059.             break;
  2060.         }
  2061.     default:
  2062.         svcerr_noproc(transp);
  2063.         return;
  2064.     }
  2065. }
  2066. X.vs
  2067. X.DE
  2068. X.
  2069. X.KS
  2070. X.NH 2
  2071. \&TCP
  2072. X.IX "TCP"
  2073. X.LP
  2074. Here is an example that is essentially
  2075. X.I rcp
  2076. The initiator of the RPC
  2077. X.I snd
  2078. call takes its standard input and sends it to the server
  2079. X.I rcv
  2080. which prints it on standard output.
  2081. The RPC call uses TCP.
  2082. This also illustrates an XDR procedure that behaves differently
  2083. on serialization than on deserialization.
  2084. X.ie t .DS
  2085. X.el .DS L
  2086. X.vs 11
  2087. X.ft I
  2088. /*
  2089.  * The xdr routine:
  2090.  *        on decode, read from wire, write onto fp
  2091.  *        on encode, read from fp, write onto wire
  2092.  */
  2093. X.ft CW
  2094. #include <stdio.h>
  2095. #include <rpc/rpc.h>
  2096.  
  2097. xdr_rcp(xdrs, fp)
  2098.     XDR *xdrs;
  2099.     FILE *fp;
  2100. {
  2101.     unsigned long size;
  2102.     char buf[BUFSIZ], *p;
  2103.  
  2104.     if (xdrs->x_op == XDR_FREE)/* nothing to free */
  2105.         return 1;
  2106.     while (1) {
  2107.         if (xdrs->x_op == XDR_ENCODE) {
  2108.             if ((size = fread(buf, sizeof(char), BUFSIZ,
  2109.               fp)) == 0 && ferror(fp)) {
  2110.                 fprintf(stderr, "can't fread\en");
  2111.                 exit(1);
  2112.             }
  2113.         }
  2114.         p = buf;
  2115.         if (!xdr_bytes(xdrs, &p, &size, BUFSIZ))
  2116.             return 0;
  2117.         if (size == 0)
  2118.             return 1;
  2119.         if (xdrs->x_op == XDR_DECODE) {
  2120.             if (fwrite(buf, sizeof(char), size,
  2121.               fp) != size) {
  2122.                 fprintf(stderr, "can't fwrite\en");
  2123.                 exit(1);
  2124.             }
  2125.         }
  2126.     }
  2127. }
  2128. X.vs
  2129. X.DE
  2130. X.KE
  2131. X.ie t .DS
  2132. X.el .DS L
  2133. X.vs 11
  2134. X.ft I
  2135. /*
  2136.  * The sender routines
  2137.  */
  2138. X.ft CW
  2139. #include <stdio.h>
  2140. #include <netdb.h>
  2141. #include <rpc/rpc.h>
  2142. #include <sys/socket.h>
  2143. #include <sys/time.h>
  2144.  
  2145. main(argc, argv)
  2146.     int argc;
  2147.     char **argv;
  2148. {
  2149.     int xdr_rcp();
  2150.     int err;
  2151.  
  2152.     if (argc < 2) {
  2153.         fprintf(stderr, "usage: %s servername\en", argv[0]);
  2154.         exit(-1);
  2155.     }
  2156.     if ((err = callrpctcp(argv[1], RCPPROG, RCPPROC,
  2157.       RCPVERS, xdr_rcp, stdin, xdr_void, 0) != 0)) {
  2158.         clnt_perrno(err);
  2159.         fprintf(stderr, "can't make RPC call\en");
  2160.         exit(1);
  2161.     }
  2162. }
  2163.  
  2164. callrpctcp(host, prognum, procnum, versnum,
  2165.            inproc, in, outproc, out)
  2166.     char *host, *in, *out;
  2167.     xdrproc_t inproc, outproc;
  2168. {
  2169.     struct sockaddr_in server_addr;
  2170.     int socket = RPC_ANYSOCK;
  2171.     enum clnt_stat clnt_stat;
  2172.     struct hostent *hp;
  2173.     register CLIENT *client;
  2174.     struct timeval total_timeout;
  2175.  
  2176.     if ((hp = gethostbyname(host)) == NULL) {
  2177.         fprintf(stderr, "can't get addr for '%s'\en", host);
  2178.         exit(-1);
  2179.     }
  2180.     bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
  2181.         hp->h_length);
  2182.     server_addr.sin_family = AF_INET;
  2183.     server_addr.sin_port =  0;
  2184.     if ((client = clnttcp_create(&server_addr, prognum,
  2185.       versnum, &socket, BUFSIZ, BUFSIZ)) == NULL) {
  2186.         perror("rpctcp_create");
  2187.         exit(-1);
  2188.     }
  2189.     total_timeout.tv_sec = 20;
  2190.     total_timeout.tv_usec = 0;
  2191.     clnt_stat = clnt_call(client, procnum,
  2192.         inproc, in, outproc, out, total_timeout);
  2193.     clnt_destroy(client);
  2194.     return (int)clnt_stat;
  2195. }
  2196. X.vs
  2197. X.DE
  2198. X.ie t .DS
  2199. X.el .DS L
  2200. X.vs 11
  2201. X.ft I
  2202. /*
  2203.  * The receiving routines
  2204.  */
  2205. X.ft CW
  2206. #include <stdio.h>
  2207. #include <rpc/rpc.h>
  2208.  
  2209. main()
  2210. {
  2211.     register SVCXPRT *transp;
  2212.      int rcp_service(), xdr_rcp(); 
  2213.  
  2214.     if ((transp = svctcp_create(RPC_ANYSOCK,
  2215.       BUFSIZ, BUFSIZ)) == NULL) {
  2216.         fprintf("svctcp_create: error\en");
  2217.         exit(1);
  2218.     }
  2219.     pmap_unset(RCPPROG, RCPVERS);
  2220.     if (!svc_register(transp,
  2221.       RCPPROG, RCPVERS, rcp_service, IPPROTO_TCP)) {
  2222.         fprintf(stderr, "svc_register: error\en");
  2223.         exit(1);
  2224.     }
  2225.     svc_run();  /* \fInever returns\fP */
  2226.     fprintf(stderr, "svc_run should never return\en");
  2227. }
  2228.  
  2229. rcp_service(rqstp, transp)
  2230.     register struct svc_req *rqstp;
  2231.     register SVCXPRT *transp;
  2232. {
  2233.     switch (rqstp->rq_proc) {
  2234.     case NULLPROC:
  2235.         if (svc_sendreply(transp, xdr_void, 0) == 0) {
  2236.             fprintf(stderr, "err: rcp_service");
  2237.             exit(1);
  2238.         }
  2239.         return;
  2240.     case RCPPROC_FP:
  2241.         if (!svc_getargs(transp, xdr_rcp, stdout)) {
  2242.             svcerr_decode(transp);
  2243.             return;
  2244.         }
  2245.         if (!svc_sendreply(transp, xdr_void, 0)) {
  2246.             fprintf(stderr, "can't reply\en");
  2247.             return;
  2248.         }
  2249.         exit(0);
  2250.     default:
  2251.         svcerr_noproc(transp);
  2252.         return;
  2253.     }
  2254. }
  2255. X.vs
  2256. X.DE
  2257. X.
  2258. X.NH 2
  2259. \&Callback Procedures
  2260. X.IX RPC "callback procedures"
  2261. X.LP
  2262. Occasionally, it is useful to have a server become a client,
  2263. and make an RPC call back the process which is its client.
  2264. An example is remote debugging,
  2265. where the client is a window system program,
  2266. and the server is a debugger running on the remote machine.
  2267. Most of the time,
  2268. the user clicks a mouse button at the debugging window,
  2269. which converts this to a debugger command,
  2270. and then makes an RPC call to the server
  2271. (where the debugger is actually running),
  2272. telling it to execute that command.
  2273. However, when the debugger hits a breakpoint, the roles are reversed,
  2274. and the debugger wants to make an rpc call to the window program,
  2275. so that it can inform the user that a breakpoint has been reached.
  2276. X.LP
  2277. In order to do an RPC callback,
  2278. you need a program number to make the RPC call on.
  2279. Since this will be a dynamically generated program number,
  2280. it should be in the transient range,
  2281. X.I "0x40000000 - 0x5fffffff" .
  2282. The routine
  2283. X.I gettransient
  2284. returns a valid program number in the transient range,
  2285. and registers it with the portmapper.
  2286. It only talks to the portmapper running on the same machine as the
  2287. X.I gettransient
  2288. routine itself.  The call to
  2289. X.I pmap_set
  2290. is a test and set operation,
  2291. in that it indivisibly tests whether a program number
  2292. has already been registered,
  2293. and if it has not, then reserves it.  On return, the
  2294. X.I sockp
  2295. argument will contain a socket that can be used
  2296. as the argument to an
  2297. X.I svcudp_create
  2298. or
  2299. X.I svctcp_create
  2300. call.
  2301. X.ie t .DS
  2302. X.el .DS L
  2303. X.ft CW
  2304. X.vs 11
  2305. #include <stdio.h>
  2306. #include <rpc/rpc.h>
  2307. #include <sys/socket.h>
  2308.  
  2309. gettransient(proto, vers, sockp)
  2310.     int proto, vers, *sockp;
  2311. {
  2312.     static int prognum = 0x40000000;
  2313.     int s, len, socktype;
  2314.     struct sockaddr_in addr;
  2315.  
  2316.     switch(proto) {
  2317.         case IPPROTO_UDP:
  2318.             socktype = SOCK_DGRAM;
  2319.             break;
  2320.         case IPPROTO_TCP:
  2321.             socktype = SOCK_STREAM;
  2322.             break;
  2323.         default:
  2324.             fprintf(stderr, "unknown protocol type\en");
  2325.             return 0;
  2326.     }
  2327.     if (*sockp == RPC_ANYSOCK) {
  2328.         if ((s = socket(AF_INET, socktype, 0)) < 0) {
  2329.             perror("socket");
  2330.             return (0);
  2331.         }
  2332.         *sockp = s;
  2333.     }
  2334.     else
  2335.         s = *sockp;
  2336.     addr.sin_addr.s_addr = 0;
  2337.     addr.sin_family = AF_INET;
  2338.     addr.sin_port = 0;
  2339.     len = sizeof(addr);
  2340. X.ft I
  2341.     /*
  2342.      * may be already bound, so don't check for error
  2343.      */
  2344. X.ft CW
  2345.     bind(s, &addr, len);
  2346.     if (getsockname(s, &addr, &len)< 0) {
  2347.         perror("getsockname");
  2348.         return (0);
  2349.     }
  2350.     while (!pmap_set(prognum++, vers, proto, 
  2351.         ntohs(addr.sin_port))) continue;
  2352.     return (prognum-1);
  2353. }
  2354. X.vs
  2355. X.DE
  2356. X.I
  2357. NOTE:
  2358. The call to
  2359. X.I ntohs
  2360. is necessary to ensure that the port number in
  2361. X.I "addr.sin_port" ,
  2362. which is in 
  2363. X.I network 
  2364. byte order, is passed in 
  2365. X.I host
  2366. byte order (as
  2367. X.I pmap_set 
  2368. expects).  This works on all Sun machines.  See the 
  2369. X.I byteorder (3N)
  2370. man page for more details on the conversion of network
  2371. addresses from network to host byte order.
  2372. X.KS
  2373. X.LP
  2374. The following pair of programs illustrate how to use the
  2375. X.I gettransient
  2376. routine.
  2377. The client makes an RPC call to the server,
  2378. passing it a transient program number.
  2379. Then the client waits around to receive a callback
  2380. from the server at that program number.
  2381. The server registers the program
  2382. X.I EXAMPLEPROG
  2383. so that it can receive the RPC call
  2384. informing it of the callback program number.
  2385. Then at some random time (on receiving an
  2386. X.I ALRM
  2387. signal in this example), it sends a callback RPC call,
  2388. using the program number it received earlier.
  2389. X.ie t .DS
  2390. X.el .DS L
  2391. X.vs 11
  2392. X.ft I
  2393. /*
  2394.  * client
  2395.  */
  2396. X.ft CW
  2397. #include <stdio.h>
  2398. #include <rpc/rpc.h>
  2399.  
  2400. int callback();
  2401. char hostname[256];
  2402.  
  2403. main()
  2404. {
  2405.     int x, ans, s;
  2406.     SVCXPRT *xprt;
  2407.  
  2408.     gethostname(hostname, sizeof(hostname));
  2409.     s = RPC_ANYSOCK;
  2410.     x = gettransient(IPPROTO_UDP, 1, &s);
  2411.     fprintf(stderr, "client gets prognum %d\en", x);
  2412.     if ((xprt = svcudp_create(s)) == NULL) {
  2413.       fprintf(stderr, "rpc_server: svcudp_create\en");
  2414.         exit(1);
  2415.     }
  2416. X.ft I
  2417.     /* protocol is 0 - gettransient() does registering
  2418.      */
  2419. X.ft CW
  2420.     (void)svc_register(xprt, x, 1, callback, 0);
  2421.     ans = callrpc(hostname, EXAMPLEPROG, EXAMPLEVERS,
  2422.         EXAMPLEPROC_CALLBACK, xdr_int, &x, xdr_void, 0);
  2423.     if ((enum clnt_stat) ans != RPC_SUCCESS) {
  2424.         fprintf(stderr, "call: ");
  2425.         clnt_perrno(ans);
  2426.         fprintf(stderr, "\en");
  2427.     }
  2428.     svc_run();
  2429.     fprintf(stderr, "Error: svc_run shouldn't return\en");
  2430. }
  2431.  
  2432. callback(rqstp, transp)
  2433.     register struct svc_req *rqstp;
  2434.     register SVCXPRT *transp;
  2435. {
  2436.     switch (rqstp->rq_proc) {
  2437.         case 0:
  2438.             if (!svc_sendreply(transp, xdr_void, 0)) {
  2439.                 fprintf(stderr, "err: rusersd\en");
  2440.                 exit(1);
  2441.             }
  2442.             exit(0);
  2443.         case 1:
  2444.             if (!svc_getargs(transp, xdr_void, 0)) {
  2445.                 svcerr_decode(transp);
  2446.                 exit(1);
  2447.             }
  2448.             fprintf(stderr, "client got callback\en");
  2449.             if (!svc_sendreply(transp, xdr_void, 0)) {
  2450.                 fprintf(stderr, "err: rusersd");
  2451.                 exit(1);
  2452.             }
  2453.     }
  2454. }
  2455. X.vs
  2456. X.DE
  2457. X.KE
  2458. X.ie t .DS
  2459. X.el .DS L
  2460. X.vs 11
  2461. X.ft I
  2462. /*
  2463.  * server
  2464.  */
  2465. X.ft CW
  2466. #include <stdio.h>
  2467. #include <rpc/rpc.h>
  2468. #include <sys/signal.h>
  2469.  
  2470. char *getnewprog();
  2471. char hostname[256];
  2472. int docallback();
  2473. int pnum;        /* \fIprogram number for callback routine\fP */
  2474.  
  2475. main()
  2476. {
  2477.     gethostname(hostname, sizeof(hostname));
  2478.     registerrpc(EXAMPLEPROG, EXAMPLEVERS,
  2479.       EXAMPLEPROC_CALLBACK, getnewprog, xdr_int, xdr_void);
  2480.     fprintf(stderr, "server going into svc_run\en");
  2481.     signal(SIGALRM, docallback);
  2482.     alarm(10);
  2483.     svc_run();
  2484.     fprintf(stderr, "Error: svc_run shouldn't return\en");
  2485. }
  2486.  
  2487. char *
  2488. getnewprog(pnump)
  2489.     char *pnump;
  2490. {
  2491.     pnum = *(int *)pnump;
  2492.     return NULL;
  2493. }
  2494.  
  2495. docallback()
  2496. {
  2497.     int ans;
  2498.  
  2499.     ans = callrpc(hostname, pnum, 1, 1, xdr_void, 0,
  2500.         xdr_void, 0);
  2501.     if (ans != 0) {
  2502.         fprintf(stderr, "server: ");
  2503.         clnt_perrno(ans);
  2504.         fprintf(stderr, "\en");
  2505.     }
  2506. }
  2507. X.vs
  2508. X.DE
  2509. Funky_Stuff
  2510. cd ..
  2511. echo more files to follow
  2512. exit
  2513.